/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

package com.facebook.drawee.drawable;

import com.facebook.common.internal.VisibleForTesting;
import com.facebook.media.ExifInterface;
import com.oszc.bbhmlibrary.utils.LogUtil;
import ohos.agp.components.element.Element;
import ohos.agp.render.Canvas;
import ohos.agp.utils.Matrix;
import ohos.agp.utils.Rect;
import ohos.agp.utils.RectFloat;

/**
 * Drawable that automatically rotates the underlying drawable with a pivot in the center of the
 * drawable bounds based on a rotation angle.
 */
public class OrientedDrawable extends ForwardingDrawable {

  private static final String TAG = "OrientedDrawable";
  @VisibleForTesting final Matrix mRotationMatrix;
  private int mRotationAngle;
  private int mExifOrientation;

  // Temporary objects preallocated in advance to save future allocations.
  private final Matrix mTempMatrix = new Matrix();
  private final RectFloat mTempRectF = new RectFloat();

  /**
   * Creates a new OrientedDrawable.
   *
   * @param rotationAngle multiples of 90 or -1 if the angle is unknown
   */
  public OrientedDrawable(Element drawable, int rotationAngle) {
    this(drawable, rotationAngle, ExifInterface.ORIENTATION_UNDEFINED);
  }

  /**
   * Creates a new OrientedDrawable.
   *
   * @param rotationAngle multiples of 90. Invalid value is clamped to a closest multiple of 90.
   * @param exifOrientation EXIF values (1-8), or 0 if unknown. Invalid value is replaced with 0.
   */
  public OrientedDrawable(Element drawable, int rotationAngle, int exifOrientation) {
    super(drawable);
    mRotationMatrix = new Matrix();
    mRotationAngle = rotationAngle - rotationAngle % 90;
    mExifOrientation =
        exifOrientation >= 0 && exifOrientation <= 8
            ? exifOrientation
            : ExifInterface.ORIENTATION_UNDEFINED;
  }

  @Override
  public void drawToCanvas(Canvas canvas) {
    LogUtil.error(TAG,"drawToCanvas =  =================================================================");
    if (mRotationAngle <= 0
        && (mExifOrientation == ExifInterface.ORIENTATION_UNDEFINED
            || mExifOrientation == ExifInterface.ORIENTATION_NORMAL)) {
      super.drawToCanvas(canvas);
      return;
    }
    int saveCount = canvas.save();
    canvas.concat(mRotationMatrix);
    super.drawToCanvas(canvas);
    canvas.restoreToCount(saveCount);
  }

  @Override
  public int getIntrinsicWidth() {
    if (mExifOrientation == ExifInterface.ORIENTATION_TRANSPOSE
        || mExifOrientation == ExifInterface.ORIENTATION_TRANSVERSE
        || mRotationAngle % 180 != 0) {
      return super.getIntrinsicHeight();
    } else {
      return super.getIntrinsicWidth();
    }
  }

  @Override
  public int getIntrinsicHeight() {
    if (mExifOrientation == ExifInterface.ORIENTATION_TRANSPOSE
        || mExifOrientation == ExifInterface.ORIENTATION_TRANSVERSE
        || mRotationAngle % 180 != 0) {
      return super.getIntrinsicWidth();
    } else {
      return super.getIntrinsicHeight();
    }
  }

  @Override
  public void setBounds(Rect bounds) {
    LogUtil.error(TAG,"setBounds = " + bounds + "; =================================================================");
    Element underlyingDrawable = getCurrentElement();
    if (mRotationAngle > 0
        || (mExifOrientation != ExifInterface.ORIENTATION_UNDEFINED
            && mExifOrientation != ExifInterface.ORIENTATION_NORMAL)) {
      switch (mExifOrientation) {
        case ExifInterface.ORIENTATION_FLIP_HORIZONTAL:
          mRotationMatrix.setScale(-1, 1);
          break;
        case ExifInterface.ORIENTATION_FLIP_VERTICAL:
          mRotationMatrix.setScale(1, -1);
          break;
        case ExifInterface.ORIENTATION_TRANSPOSE:
          mRotationMatrix.setRotate(270, bounds.getCenterX(), bounds.getCenterY());
          mRotationMatrix.postScale(1, -1);
          break;
        case ExifInterface.ORIENTATION_TRANSVERSE:
          mRotationMatrix.setRotate(270, bounds.getCenterX(), bounds.getCenterY());
          mRotationMatrix.postScale(-1, 1);
          break;
        default:
          mRotationMatrix.setRotate(mRotationAngle, bounds.getCenterX(), bounds.getCenterY());
          break;
      }

      // Set the rotated bounds on the underlying drawable
      mTempMatrix.reset();
      mRotationMatrix.invert(mTempMatrix);
      mTempRectF.left = bounds.left;
      mTempRectF.right = bounds.right;
      mTempRectF.top = bounds.top;
      mTempRectF.bottom = bounds.bottom;
      mTempMatrix.mapRect(mTempRectF);
      underlyingDrawable.setBounds(
          (int) mTempRectF.left,
          (int) mTempRectF.top,
          (int) mTempRectF.right,
          (int) mTempRectF.bottom);
      //super.setBounds(bounds);
    } else {
      //super.setBounds(bounds);
     underlyingDrawable.setBounds(bounds);
    }
  }

  @Override
  public void getTransform(Matrix transform) {
    getParentTransform(transform);
    if (!mRotationMatrix.isIdentity()) {
      transform.preConcat(mRotationMatrix);
    }
  }

}
